from EasyDebugger import *
import re
from random import *
import crumbs
import EasyXML

DEBUG_REMOVE = getDebugFlag()
DEBUG_RANDOM = getDebugFlag()
DEBUG_SPILL = getDebugFlag()
DEBUG_SET = getDebugFlag()
DEBUG_IF = getDebugFlag()
DEBUG_KILL = getDebugFlag()

#addLevel(DEBUG_REMOVE + DEBUG_RANDOM + DEBUG_SPILL + DEBUG_SET + DEBUG_IF)
#addLevel(DEBUG_IF)

def retract(node):
    #retract previously selected nodes
    if hasattr(node, "_retl"):
        for item in node._retl:
            debug(DEBUG_RANDOM, "Retracting " + item._name + " from " + item._parent._name + " to " + node._name)
            item._parent._children.remove(item)
            item._parent = node
            retract(item) #make sure to retract anything, dont leave stranded children!
            
    node._retl = []

def register(parser):
    def nodePrint(self, node):
        print self.parseText(node._parent, node._textblock()) 
        return (1, [])
    
    def nodeDebug(self, node):
        if hasattr(node, "path"):
            node = parsePath(node._parent, node.path)
        else:
            node = node._parent
        
        print node
        
        return (1, [])
    
    def nodeRemove(self, node):
        ret = 1
        if hasattr(node, "type") and node.type is "static":
            ret = 0
        if hasattr(node, "if") and not self.parseMath(node._parent, getattr(node, "if")): #using node.if gives problems, this is a simple workaround
            return (ret, [])
        point = self.parsePath(node._parent, node.path)
        if point == False:
            debug(DEBUG_REMOVE, "Remove not found: " + node.path)
            return (ret, [])
        
        for i in range(0, len(point._parent._children)):
            if point._parent._children[i] == point:
                debug(DEBUG_REMOVE, "Removed " + node.path + " named " + point._parent._children[i]._name)
                point._parent._children[i] = None
                del point
                break
            
        return (ret, [])
    
    def nodeRandom(self, node):
        #grab data
        
        ret = 1
            
        #check if we are static or dynamic.
        if hasattr(node, "type") is False:
            node.type = "dynamic"
        elif node.type == "once":
            ret = 0
            
        if hasattr(node, "weighted") is False:
            node.weighted = "no"
      
        retract(node)
        
        #parse the if conditional. If its false, break.
        if hasattr(node, "if") and not self.parseMath(node._parent, getattr(node, "if")): #using node.if gives problems, this is a simple workaround
            return (ret, [])
        
        #n is the base number selected
        if hasattr(node, "n") is False:
            node.n = 1
        else:
            if type(node.n) != type(1):
                node.n = int(self.parseMath(node, node.n))
            
        #up to r additional choices selected
        if hasattr(node, "r") is True:
            if type(node.r) != type(1):
                node.r = int(self.parseMath(node, node.r))
        else:
            node.r = 0
            
        list = []
        #make a deep copy of node._children: We don't want to alter it!
        for item in node._children: 
            list.append(item)
        
        debug(DEBUG_RANDOM, "Parsing " + str(node.n) + " random " + node.type + " nodes")
        
        #preparse
        if hasattr(node, "parse"):
            debug(DEBUG_RANDOM, "Preparsing " + node.parse)
            parse = []
            regex = re.compile(node.parse)
            for item in list:
                if regex.match(item._name) is not None:
                    debug(DEBUG_RANDOM, "Pre-Parsing " + item._name)
                    parse.append(item)
                    list.remove(item)
                    
            self.parseList(parse)
                
            for cnode in parse:
                list.append(cnode)
        
        #select nodes here: we don't want to remove them but we do want to only select them once.
        #a range is used so that we can subtract numbers from the range.
        selrange = range(len(list))
        
        #multiply weighted nodes
        for i in range(len(list)):
            if hasattr(list[i], "r_weight"):
                x = int(list[i].r_weight) - 1
                selrange.extend([i] * x) #add weighted nodes to the end.
                
        n = randint(node.n, node.n + node.r) #dont change the actual N value!
        while(n > 0):
            sel = randint(0, len(selrange) - 1)
            node._retl.append(list[selrange[sel]])
            list[selrange[sel]]._parent = node._parent
            selrange.pop(sel) #delete from the range so we don't select it again.
            n -= 1
        
        return (ret, node._retl)
    
    def nodeSpill(self, node):
        ret = 1
        
        #check if we are static or dynamic.
        if hasattr(node, "type") is False:
            node.type = "dynamic"
        elif node.type == "once":
            ret = 0
            
        retract(node)
        
        #parse the if conditional. If its false, break.
        if hasattr(node, "if") and not self.parseMath(node._parent, getattr(node, "if")): #using node.if gives problems, this is a simple workaround
            return (ret, [])
        
        #parse the path
        point = self.parsePath(node._parent, node.path)
        if point == False:
            debug(DEBUG_SPILL, "Cannot find spill target: " + node.path)
            return (ret, [])
        debug(DEBUG_SPILL, "Spilling into " + point._name)
        
        #inster them into the pathed location
        for child in node._children:
            point._children.append(child)
            child._parent = point
            
        node._retl = node._children
        
        return (ret, [])
    
    def nodeSet(self, node):
        ret = 1
        
        #check if we are static or dynamic.
        if hasattr(node, "type") is False:
            node.type = "dynamic"
        elif node.type == "once":
            ret = 0
        
        #parse the if conditional. If its false, break.
        if hasattr(node, "if") and not self.parseMath(node._parent, getattr(node, "if")): #using node.if gives problems, this is a simple workaround
            return (ret, [])
        
        #grab the path first
        sp = node.path.split(".")
        point = self.parsePath(node._parent, sp[0])
        
        if point != 0:
            #figure out the value
            value = str(self.parseMath(node._parent, node.value))
            setattr(point, sp[1], value)
            debug(DEBUG_SET, "Set: " + point._name + "." + sp[1] + " to " + value)
        else:
            debug(DEBUG_SET, "Set " + sp[0] + "." + sp[1] + " not found.")
            
        
        return (ret, [])
    
    def nodeSetrand(self, node):
        
        ret = 1
        
        #check if we are static or dynamic.
        if hasattr(node, "type") is False:
            node.type = "dynamic"
        elif node.type == "once":
            ret = 0
        
        #parse the if conditional. If its false, break.
        if hasattr(node, "if") and not self.parseMath(node._parent, getattr(node, "if")): #using node.if gives problems, this is a simple workaround
            return (ret, [])
        
        #grab the path first
        sp = node.path.split(".")
        point = self.parsePath(node._parent, sp[0])
        
        if point != 0:
            #figure out the value
            selected = node._text[randint(0, len(node._text) - 1)] #THE ONLY DIFFERENCE. Kinda depressing...
            value = str(self.parseMath(node._parent, selected))
            setattr(point, sp[1], value)
            debug(DEBUG_SET, "Set: " + point._name + "." + sp[1] + " to " + value)
        else:
            debug(DEBUG_SET, "Set " + sp[0] + "." + sp[1] + " not found.")
            
        
        return (ret, [])
    
    def nodeIf(self, node):
        #grab data
        
        ret = 1
            
        #check if we are static or dynamic.
        if hasattr(node, "type") is False:
            node.type = "dynamic"
        elif node.type == "once":
            ret = 0
      
        retract(node)
                
        
        if hasattr(node, "_else") is False: #search for an else tag and remove it from the children if found
                                            #mucks up structure but for a good cause.
            node._else = None
            for item in node._children:
                if item._name == "else":
                    node._else = item
                    node._children.remove(item)
                    break
        
        #parse the if conditional. If its false, use the else tag if appropriate.
        if not self.parseMath(node._parent, node.expr):
            debug(DEBUG_IF, "If " + node.expr + " false.")
            if node._else is not None:
                for item in node._else._children: 
                    node._retl.append(item)
                    item._parent = node._parent
            else:
                return (ret, [])
        else:
            debug(DEBUG_IF, "If " + node.expr + " true. Yay!")
            #make a deep copy of node._children: We don't want to alter it!
            for item in node._children: 
                node._retl.append(item)
                item._parent = node._parent
                
        node._retl.reverse()
        
        return (ret, node._retl)
    
    def nodeFirst(self, node):
        #grab data
        
        ret = 1
            
        #check if we are static or dynamic.
        if hasattr(node, "type") is False:
            node.type = "dynamic"
        elif node.type == "once":
            ret = 0
      
        retract(node)
        
        #parse the if conditional. If its false, use the else tag if appropriate.
        if hasattr(node, "n"):
            n = int(self.parseMath(node, node.n))
        else:
            n = 1
            
        for child in node._children:
            #parse default condition
            if child._name == "default": #if we ran into this, then it better be the last, and N > 0
                for item in child._children:
                    node._retl.append(item)
                    item._parent = node._parent
                break
            #this expression is true.
            elif self.parseMath(node._parent, child.expr):
                #add childrens
                for item in child._children:
                    node._retl.append(item)
                    item._parent = node._parent
                    
                n -= 1
                if n <= 0:
                    break
                
        node._retl.reverse()
        
        return (ret, node._retl)
    
    #NOT IMPLEMENTED ATM
    def nodeEnsure(self, node):
        ret = 1
        
        #check if we are static or dynamic.
        if hasattr(node, "type") is False:
            node.type = "dynamic"
        elif node.type == "once":
            ret = 0
        
        if hasattr(node, "n"):
            n = int(self.parseMath(node, node.n))
        else:
            n = 1
            
        retract(node)
            
        #find selection type
        if hasattr(node, "selection") is False:
            node.selection = "random"
            
        #loop through children, mark false children.
        false = []
        for child in node._children:
            #is the expr true? If so, decrement n
            if self.parseMath(node._parent, child.expr):
                n -= 1
                #we ensured enough, stop now.
                if n <= 0:
                    break
            else:
                false.append(child)
                
        if node.selection == "random":
            shuffle(false)
            
        while n > 0:
            if len(false) == 0:
                break #dont keep trying if theres not enough!!
            
            #append childs
            child = false.pop(0)
            for item in child._children:
                node._retl.append(item)
                item._parent = node._parent
                
            n -= 1
                
        node._retl.reverse()
        
        return (ret, node._retl)
    
    def nodeDo(self, node):
        retract(node)
        
        for item in node._children: 
                node._retl.append(item)
                item._parent = node._parent
                
        node._retl.reverse()
        return (1, node._retl)
    
    def nodeTrail(self, node):
        #get the other file
        trail = EasyXML.getXML(node.file)
        xml = EasyXML.parseXML(trail.documentElement)
        xml._parent = node
        node._children.append(xml)
        #parse it and add it to the childs
        result = self.parseCrumb(xml)
        
        if result[0] == 0:
            node._children.remove(xml)

        for child in result[1]:
            node._children.append(child)
            
        return (0, node._children)
    
    def nodeKill(self, node):
        ret = 1
        
        #check if we are static or dynamic.
        if hasattr(node, "type") is False:
            node.type = "dynamic"
        elif node.type == "once":
            ret = 0
        
        #parse the if conditional. If its false, break.
        if hasattr(node, "if") and not self.parseMath(node._parent, getattr(node, "if")): #using node.if gives problems, this is a simple workaround
            return (ret, [])
        
        #grab the path 
        point = self.parsePath(node._parent, node.path)
        
        if point != 0:
            #1...2...3...kill it!
            point._parent._children.remove(point)
            point._parent = None
            debug(DEBUG_KILL, "Killed: " + point._name)
        else:
            debug(DEBUG_KILL, "Kill target " + node.path + " not found.")
            
        
        return (ret, [])
    
    def pathRoot(self, node):
        while node._parent is not None:
            node = node._parent
        return node
    
    def pathParent(self, node):
        if node._parent is not None:
            return node._parent
        
        return False
        
    parser.registerFunc("print", nodePrint)
    parser.registerFunc("debug", nodeDebug)
    parser.registerFunc("remove", nodeRemove)
    parser.registerFunc("random", nodeRandom)
    parser.registerFunc("spill", nodeSpill)
    parser.registerFunc("set", nodeSet)
    parser.registerFunc("setrand", nodeSetrand)
    parser.registerFunc("if", nodeIf)
    parser.registerFunc("first", nodeFirst)
    parser.registerFunc("ensure", nodeEnsure)
    parser.registerFunc("do", nodeDo)
    parser.registerFunc("trail", nodeTrail)
    parser.registerFunc("kill", nodeKill)
    parser.registerTextFunc("root", pathRoot)
    parser.registerTextFunc("parent", pathParent)
